#!/usr/bin/python
import re
import os
import utility
import collections

class SitesPlugin:
    """
    Match
    #define GUID_######## "########" /* This is comments. */
    """
    reg_guid_definition = '\#define GUID\_([A-Z0-9_.]{1,8})\s+\"([A-Z0-9_.]{1,8})\"\s+\/\* .+ \*\/'
    
    """
    Match 
    { "HTTP", "User-Agent", "*****.***", GUID_########, 1 },
    { "TLS", "Host", "*****.***", GUID_########, 0 },
    """
    reg_rule = '\{ \"(HTTP|TLS)\"\, \"(Host|Referer|User-Agent)\"\, \"(.+)\"\, (GUID\_[A-Z0-9_.]{1,8})\, [01] \}\,'
    
    def valid_guid_definition(self, definition):
        return re.match(SitesPlugin.reg_guid_definition, definition) is not None or False
        
    def valid_rules(self, rule):
        return re.match(SitesPlugin.reg_rule, rule) is not None or False
    
    def check_guid_format(self, guid_file):
        """
        Check if there are duplicated guid definition in guid.h
        
        Arguments:
        guid_path -- file contains guid definitions
        
        Returns:
        output -- a list consist of guid definitions in wrong format
        
        """
        dictionary = {}
        output = []
        if not os.path.isfile(guid_file):
            return output
        
        with open(guid_file, 'r') as guid_list:
            for line in guid_list.readlines():
                if not line.find("#define"):                        # make sure not comments 
                    if self.valid_guid_definition(line):            # check if it is correct format 
                        guid = re.match(SitesPlugin.reg_guid_definition, line)
                        if guid.group(1) == guid.group(2):          # make sure GUID_### matches "###"
                            if dictionary.has_key(guid.group(1)):   # check duplicates
                                output.append("Duplicate: " + line)
                            else:
                                dictionary[guid.group(1)] = guid.group(1)
                        else:
                            output.append("TWO GUID NOT MATCH: " + line)
                    else:
                        output.append("WRONG FORMAT: " + line)
        output_f = utility.File()
        output_f.writeFile(output, guid_file + "_not_match.txt")
        guid_list.close()
        return output
    
    def check_rule_format(self, rule_file):
        """
        Check if there are duplicated rule
        
        Arguments:
        guid_path -- file contains rules
        
        Returns:
        output -- a list consist of rules in wrong format
        
        """
        dictionary = {}
        output = []
        if not os.path.isfile(rule_file):
            return output
        
        with open(rule_file, 'r') as rule_list:
            for line in rule_list.readlines():
                if not line.find("{"):                          # make sure not comments
                    if self.valid_rules(line):                  # check if it is correct format
                        if dictionary.has_key(line):            # check duplicates
                            output.append("Duplicate: " + line)
                        else:
                            dictionary[line] = line
                    else:
                        output.append("WRONG FORMAT: " + line)
        output_f = utility.File()
        output_f.writeFile(output, rule_file + "_not_match.txt")
        rule_list.close()
        return output
    
    def find_guid(self, guid_file):
        output_list = []
        if os.path.isfile(guid_file):
            with open(guid_file, 'r') as guid_list:
                guids = re.findall('GUID\_([A-Z0-9_.]{1,8})', guid_list.read())
                for guid in guids:
                    output_list.append(guid + "\n")
            output_f = utility.File()
            output_f.writeFile(output_list, guid_file + "_find_guid.txt")
        else:
            print "Not a valid guid file: " + guid_file
                    
                     
        

    def format_pattern_sites(self, header, pattern, http, tls, guid):
        output = "Sites, " + header + ", " + pattern + ", " + http + ", " + tls + ", " + guid + ", n,"
        return output
    
    def format_pattern_ads_sites(self, header, pattern, http, tls, guid):
        output = "Sites, " + header + ", " + pattern + ", " + http + ", " + tls + ", " + guid + ", y, Inspect HTTP referers for subclassification"
        return output

    def format_guid(self, guid):
        if guid.find('GUID_'):
            return 'GUID_' + str(guid).upper().strip()
        return guid.upper().strip()
    
    def parse_rule(self, rule):
        """
        Make a rule like { "HTTP", "Host", "naver.com", GUID_NAVER, 0 }, --> ['Host', 'naver.com', 'y', 'n', 'GUID_NAVER']
        
        Arguments:
        rule -- string, { "HTTP", "Host", "naver.com", GUID_NAVER, 0 },
        
        Returns:
        list -- a list consist of header, rule, http, tls, guid
        
        """
        pattern = []
        parsed_list = re.match(SitesPlugin.reg_rule, rule)
        if parsed_list is not None:
            pattern.append(parsed_list.group(2))    # header
            pattern.append(parsed_list.group(3))    # rule
            if parsed_list.group(1) == "HTTP":
                pattern.append("y")                 # http
                pattern.append("n")                 # tls
            else:
                pattern.append("n")                 # http
                pattern.append("y")                 # tls
            pattern.append(parsed_list.group(4))    # guid
        else:
            print "WRONG FORMATE:\t" + rule
            return ""
        return pattern
    
    def make_webpattern_sites(self, guids_file, rules_file):
        """
        Make web pattern 
        { "HTTP", "Host", "*.naver.com", GUID_NAVER, 0 },
        { "TLS", "Host", "*.naver.com", GUID_NAVER, 0 },
        --->    Sites, Host, *.naver.com, y, y, GUID_NAVER, n,
        
        Arguments:
        rules_file -- file contains all rules like { "HTTP", "Host", "*.naver.com", GUID_NAVER, 0 },
        guids_file -- file contains all guids like GUID_NAVER or NAVER
        output_file -- file output file path
        
        Returns:
        None
        
        """
        rules_f = open(rules_file, "r")
        guids_f = open(guids_file, "r")
        guid_list = guids_f.readlines()
        rules_list = rules_f.readlines()
        dictionary = collections.OrderedDict()
        for line in rules_list:
            for guid in guid_list:
                if line.find(self.format_guid(guid)) >= 0 :
                    rule = self.parse_rule(line.strip())
                    if len(rule) > 1:
                        # if this is http, add it
                        if rule[2] == 'y':
                            dictionary[rule[1]] = rule
                        # if this is tls, check if there is a exit rule, if there is then change tls to "y", if not then add it
                        else:
                            if dictionary.has_key(rule[1]):
                                temp_list = dictionary.get(rule[1])
                                temp_list[2] = "y" # http
                                temp_list[3] = "y" # tls
                                dictionary[rule[1]] = temp_list
                            else:
                                dictionary[rule[1]] = rule
        output_file = rules_file + "_webpattern.txt"
        with open(output_file,'w+') as file_w:
            for temp_list in sorted(dictionary.values(), key=lambda value:value[4][5]):
                pattern = self.format_pattern_sites(temp_list[0], # header
                                                    temp_list[1], # rule
                                                    temp_list[2], # http
                                                    temp_list[3], # tls
                                                    temp_list[4]) # guid
                file_w.write(pattern + "\n")
        guids_f.close()
        rules_f.close()
        file_w.close()
        
    def make_webpattern_referer_sites(self, guids_file, rules_file):
        """
        Make web pattern 
        { "HTTP", "Host", "*.naver.com", GUID_NAVER, 0 },
        --->    Sites, Host, *.naver.com, y, n, GUID_NAVER, y, Inspect HTTP referers for subclassification
        { "TLS", "Host", "*.naver.com", GUID_NAVER, 0 },
        --->    Sites, Host, *.naver.com, n, y, GUID_NAVER, n,
        
        Arguments:
        rules_file -- file contains all rules like { "HTTP", "Host", "*.naver.com", GUID_NAVER, 0 },
        guids_file -- file contains all guids like GUID_NAVER or NAVER
        output_file -- file output file path
        
        Returns:
        None
        
        """
        rules_f = open(rules_file, "r")
        guids_f = open(guids_file, "r")
        guid_list = guids_f.readlines()
        rules_list = rules_f.readlines()
        dictionary = collections.OrderedDict()
        for line in rules_list:
            for guid in guid_list:
                if line.find(self.format_guid(guid)) >= 0 :
                    rule = self.parse_rule(line.strip())
                    if len(rule) > 1 :
                        dictionary[rule[1] + rule[2] + rule[3]] = rule
        output_file = rules_file + "_webpattern.txt"
        with open(output_file,'w+') as file_w:
            for temp_list in sorted(dictionary.values(), key=lambda value:value[4][5]):
                if temp_list[2] == "y":
                    pattern = self.format_pattern_ads_sites(temp_list[0], # header
                                                            temp_list[1], # rule
                                                            temp_list[2], # http
                                                            temp_list[3], # tls
                                                            temp_list[4]) # guid
                    file_w.write(pattern + "\n")
                elif temp_list[3] == "y":
                    pattern = self.format_pattern_sites(temp_list[0], # header
                                                        temp_list[1], # rule
                                                        temp_list[2], # http
                                                        temp_list[3], # tls
                                                        temp_list[4]) # guid
                    file_w.write(pattern + "\n")

        guids_f.close()
        rules_f.close()
        file_w.close()
    